//:  v.book.read.tip.statemachine2.vm.VM.java
package v.book.read.tip.statemachine2.vm;

import v.book.read.tip.statemachine2.Condition;
import v.book.read.tip.statemachine2.Input;
import v.book.read.tip.statemachine2.StateMachine;
import v.book.read.tip.statemachine2.Transition;
import v.book.read.tip.statemachine2.vm.input.FirstDigit;
import v.book.read.tip.statemachine2.vm.input.HasChange;
import v.book.read.tip.statemachine2.vm.input.Money;
import v.book.read.tip.statemachine2.vm.input.Quit;
import v.book.read.tip.statemachine2.vm.input.SecondDigit;
import v.book.read.tip.statemachine2.vm.state.VM;



// 好像没用到
class ChangeAvailable extends StateMachine {

    public ChangeAvailable() {
        super(VM.makesChange);
        buildTable(new Object[][][]{
            { {VM.makesChange}, // Current state
                // Input, test, transition, next state:
                {HasChange.no, null, null, VM.noChange}},
            { {VM.noChange}, // Current state
                // Input, test, transition, next state:
                {HasChange.yes, null, null, VM.makesChange}},
        });
    }

}

// 物品项
class ItemSlot {
    int price;
    int quantity;
    static int counter = 0;
    String id = Integer.toString(counter++);
    public ItemSlot(int prc, int quant) {
        price = prc;
        quantity = quant;
    }
    public String toString() { return id; }
    public int getPrice() { return price; }
    public int getQuantity() { return quantity; }
    public void decrQuantity() { quantity--; }
}

public class VendingMachine extends StateMachine{
    StateMachine changeAvailable = new ChangeAvailable();
    int amount = 0;
    FirstDigit first = null;
    ItemSlot[][] items = new ItemSlot[4][4]; // 4x4 个物品
    
    // 钱不够
    Condition notEnough = new Condition() {
        public boolean condition(Input input) {
            int i1 = first.getValue();
            int i2 = ((SecondDigit)input).getValue();
            return items[i1][i2].getPrice() > amount;
        }
    };
    
    // 可以购买
    Condition itemAvailable = new Condition() {
        public boolean condition(Input input) {
            int i1 = first.getValue();
            int i2 = ((SecondDigit)input).getValue();
            return items[i1][i2].getQuantity() > 0;
        }
    };
    
    // 不可购买
    Condition itemNotAvailable = new Condition() {
        public boolean condition(Input input) {
            return !itemAvailable.condition(input);
        }
    };
    
    // 详情 
    Transition clearSelection = new Transition() {
        public void transition(Input input) {
            int i1 = first.getValue();
            int i2 = ((SecondDigit)input).getValue();
            ItemSlot is = items[i1][i2];
            System.out.println(
                    "Clearing selection: item " + is +
                    " costs " + is.getPrice() +
                    " and has quantity " + is.getQuantity());
            first = null;
        }
    };
    
    // 购买
    Transition dispense = new Transition() {
        public void transition(Input input) {
            int i1 = first.getValue();
            int i2 = ((SecondDigit)input).getValue();
            ItemSlot is = items[i1][i2];
            System.out.println("Dispensing item " +
                    is + " costs " + is.getPrice() +
                    " and has quantity " + is.getQuantity());
            items[i1][i2].decrQuantity();
            System.out.println("New Quantity " + is.getQuantity());
            amount -= is.getPrice();
            System.out.println("Amount remaining " + amount);
        }
    };
    
    // 查询余额
    Transition showTotal = new Transition() {
        public void transition(Input input) {
            amount += ((Money)input).getValue();
            System.out.println("Total amount = " + amount);
        }
    };
    
    // 退钱
    Transition returnChange = new Transition() {
        public void transition(Input input) {
            System.out.println("Returning " + amount);
            amount = 0;
        }
    };
    
    // 显示第一个输入
    Transition showDigit = new Transition() {
        public void transition(Input input) {
            first = (FirstDigit)input;
            System.out.println("First Digit= "+ first);
        }
    };
    
    public VendingMachine() {
        
        super(VM.quiescent); // Initial state
        
        /** 设置数量与价格 */
        for(int i = 0; i < items.length; i++)
            for(int j = 0; j < items[i].length; j++)
                items[i][j] = new ItemSlot((j+1)*25, 5);
        items[3][0] = new ItemSlot(25, 0);
        
        /** 设置状态关系 */
        buildTable(new Object[][][]{
            { {VM.quiescent}, // Current state - 000
                // Input, test, transition, next state:
                {Money.class, null, showTotal, VM.collecting} }, // 001
                
            { {VM.collecting}, // Current state //010
                // Input, test, transition, next state:
	            {Quit.quit, null,returnChange, VM.quiescent}, // 011
	            {Money.class, null, showTotal, VM.collecting}, // 012
	            {FirstDigit.class, null, showDigit, VM.selecting}}, // 013
	            
            { {VM.selecting}, // Current state 
                // Input, test, transition, next state:
                {Quit.quit, null, returnChange, VM.quiescent},
                {SecondDigit.class, notEnough, clearSelection, VM.collecting},
	            {SecondDigit.class, itemNotAvailable, clearSelection, VM.unavailable},
	            {SecondDigit.class, itemAvailable, dispense, VM.wantMore}},
	            
            { {VM.unavailable}, // Current state
                // Input, test, transition, next state:
                {Quit.quit, null, returnChange, VM.quiescent},
                {FirstDigit.class, null, showDigit, VM.selecting}},
                
            { {VM.wantMore}, // Current state
                // Input, test, transition, next state:
                {Quit.quit, null, returnChange, VM.quiescent},
                {FirstDigit.class, null, showDigit, VM.selecting}},
        });
    }
} ///:~
